package cn.bugstack.chatglm.session.defaults;

import cn.bugstack.chatglm.IOpenAiApi;
import cn.bugstack.chatglm.executor.Executor;
import cn.bugstack.chatglm.interceptor.OpenAiHTTPInterceptor;
import cn.bugstack.chatglm.model.Model;
import cn.bugstack.chatglm.session.Configuration;
import cn.bugstack.chatglm.session.OpenAiSession;
import cn.bugstack.chatglm.session.OpenAiSessionFactory;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @description 会话工厂
 */
public class DefaultOpenAiSessionFactory implements OpenAiSessionFactory {

    private final Configuration configuration;

    public DefaultOpenAiSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public OpenAiSession openSession() {
        // 1. 日志配置，记录Http请求响应的日志，用于调试以及监控API请求
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(configuration.getLevel());

        // 2. 开启 Http 客户端，使用到OKHttpClient，它是用于与OpenAI服务器进行HTTP通信的客户端
        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(httpLoggingInterceptor)
                .addInterceptor(new OpenAiHTTPInterceptor(configuration))//配置自定义拦截器，用于在HTTP请求头里添加token等信息
                .connectTimeout(configuration.getConnectTimeout(), TimeUnit.SECONDS)
                .writeTimeout(configuration.getWriteTimeout(), TimeUnit.SECONDS)
                .readTimeout(configuration.getReadTimeout(), TimeUnit.SECONDS)//设置连接超时时间、写入超时时间、读取超时时间
                .build();
        //OkHttpClient被用来发送HTTP请求
        configuration.setOkHttpClient(okHttpClient);

        // 3. 创建 API 服务，Retrofit 是一个用于发起 HTTP 请求的库，在这里用于与 chatglm API 通信
        // 当openAiApi被调用时，也就是Test中openAisession.completions(request)执行时，Retrofit内部会调用OkHttpClient.newCall().execute() 发送 HTTP 请求，从而触发 拦截器！
        IOpenAiApi openAiApi = new Retrofit.Builder()
                .baseUrl(configuration.getApiHost())//chatglm API基础URL
                .client(okHttpClient)//使用上面创建的okHttpClient来发起请求，意味着Retroitfit内部会使用OkHttpClient发送请求
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加 RxJava 的适配器，使得请求可以支持异步操作
                .addConverterFactory(JacksonConverterFactory.create())//使用 Jackson 作为 JSON 转换器，将请求和响应的 JSON 数据转换成 Java 对象。
                .build().create(IOpenAiApi.class);

        configuration.setOpenAiApi(openAiApi);


        // 4. 实例化执行器，让你根据选择的不同模型（新模型、旧模型）走不同的执行逻辑
        HashMap<Model, Executor> executorGroup = configuration.newExecutorGroup();

        //最后，openSession() 方法会创建并返回一个 DefaultOpenAiSession 对象，并传递配置（configuration）以及执行器给它。
        // DefaultOpenAiSession 是你与 chatglm 进行交互的主要接口，通过它你可以进行各种操作，比如文本问答、图像生成、文件上传等。
        return new DefaultOpenAiSession(configuration, executorGroup);
    }

}
